﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Threading;
using SharpDX.XAudio2;
using ScheduledXAudio2;
using SynergyControls;
using SynergyLib.DSP;

namespace XAudio2Controls
{
    /// <summary>
    /// This control provides 
    /// graphical interaction 
    /// for user and app 
    /// for the Patch, Shape (incorrectly named), 
    /// Pattern (rhythm, beat, phrase etc), 
    /// Submixers (currently provides access to 4 cascading submixers each with a filter applied to it) and effects.
    /// </summary>
    internal class DrumPatchTabPanel : XA2TabPanelBase
    {
        #region Delegates
        public delegate void BarSubmitDelegate(int i);        
        public delegate void AddRhythmButtonBarDelegate();
        public delegate void MiscDelegate();
        #endregion Delegates

        #region Fields
        private Object locker = new Object();
        
        #endregion

        #region Properties
        public Channel ChannelGetter
        {
            get { return channel; }
        }
        public SubmixVoice SubMixer
        {
            get
            {
                if (SoundEngine != null)
                {                    
                    return SoundEngine.SubMixer;
                }
                return null;
            }
        }
        public Thread PThread
        {
            get { return PatchThread; }
        }
        #endregion Properties
        #region Dependency Properties
        #region RhythmButtonBars
        /// <summary>
        /// Identifies the <see cref="EqualizerValues" /> dependency property. 
        /// </summary>
        public static readonly DependencyProperty RhythmButtonBarsProperty =
            DependencyProperty.Register("RhythmButtonBars",
            typeof(ObservableCollection<RhythmButtonBar>),
            typeof(DrumPatchTabPanel),
            new PropertyMetadata(new ObservableCollection<RhythmButtonBar>(),OnRhythmButtonBarsChanged));      

        private static void OnRhythmButtonBarsChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            DrumPatchTabPanel DrumPatchTabPanel = o as DrumPatchTabPanel;
            if (DrumPatchTabPanel != null)
                DrumPatchTabPanel.OnRhythmButtonBarsChanged((ObservableCollection<RhythmButtonBar>)e.OldValue, (ObservableCollection<RhythmButtonBar>)e.NewValue);
        }        
        /// <summary>
        /// Called after the <see cref="EqualizerValues"/> value has changed.
        /// </summary>
        /// <param name="oldValue">The previous value of <see cref="EqualizerValues"/></param>
        /// <param name="newValue">The new value of <see cref="EqualizerValues"/></param>
        protected virtual void OnRhythmButtonBarsChanged(ObservableCollection<RhythmButtonBar> oldValue, ObservableCollection<RhythmButtonBar> newValue)
        {
            if (newValue == null || newValue.Count != NumberOfRhythmButtonBars)
                RhythmButtonBars = newValue;
            else
                RhythmButtonBars = newValue;
        }

        /// <summary>
        /// Gets or sets the values of each equalizer band.
        /// </summary>
        /// <remarks>The number of elements in the EqualizerValues array must be equal to the number of bands. If not, all values will be set to zero.</remarks>
        public ObservableCollection<RhythmButtonBar> RhythmButtonBars
        {
            // IMPORTANT: To maintain parity between setting a property in XAML and procedural code, do not touch the getter and setter inside this dependency property!
            get
            {
                return (ObservableCollection<RhythmButtonBar>)GetValue(RhythmButtonBarsProperty);
            }
            set
            {
                SetValue(RhythmButtonBarsProperty, value);
            }
        }
        #endregion
        #region NumberOfRhythmButtonBars
        /// <summary>
        /// Identifies the <see cref="NumberOfRhythmButtonBars" /> dependency property. 
        /// </summary>
        public static readonly DependencyProperty NumberOfRhythmButtonBarsProperty = DependencyProperty.Register("NumberOfRhythmButtonBars", typeof(int), typeof(DrumPatchTabPanel), new UIPropertyMetadata(0, OnNumberOfRhythmButtonBarsChanged));        

        private static void OnNumberOfRhythmButtonBarsChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            DrumPatchTabPanel DrumPatchTabPanel = o as DrumPatchTabPanel;
            if (DrumPatchTabPanel != null)
                DrumPatchTabPanel.OnNumberOfRhythmButtonBarsChanged((int)e.OldValue, (int)e.NewValue);
        }       

        /// <summary>
        /// Called after the <see cref="NumberOfRhythmButtonBars"/> value has changed.
        /// </summary>
        /// <param name="oldValue">The previous value of <see cref="NumberOfRhythmButtonBars"/></param>
        /// <param name="newValue">The new value of <see cref="NumberOfRhythmButtonBars"/></param>
        protected virtual void OnNumberOfRhythmButtonBarsChanged(int oldValue, int newValue)
        {
            // CreateRhythmButtonBars();
            //  SetRhythmButtonBarPatterns(new List<byte[]>());
        }

        /// <summary>
        /// Gets or sets the number of bands that the equalizer will display.
        /// </summary>
        public int NumberOfRhythmButtonBars
        {
            get
            {
                return (int)GetValue(NumberOfRhythmButtonBarsProperty);
            }
            set
            {
                SetValue(NumberOfRhythmButtonBarsProperty, value);
            }
        }

        #endregion
      
        #region Channel

        public static readonly DependencyProperty ChannelProperty = DependencyProperty.Register("Channel", typeof(Channel), typeof(DrumPatchTabPanel), new UIPropertyMetadata(Channel.Channel10, OnChannelChanged, OnCoerceChannel));

        private static object OnCoerceChannel(DependencyObject o, object value)
        {
            DrumPatchTabPanel DrumPatchTabPanel = o as DrumPatchTabPanel;
            if (DrumPatchTabPanel != null)
                return DrumPatchTabPanel.OnCoerceChannel((Channel)value);
            else
                return value;
        }

        private static void OnChannelChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            DrumPatchTabPanel DrumPatchTabPanel = o as DrumPatchTabPanel;
            if (DrumPatchTabPanel != null)
                DrumPatchTabPanel.OnChannelChanged((Channel)e.OldValue, (Channel)e.NewValue);
        }


        protected virtual Channel OnCoerceChannel(Channel value)
        {

            return value;
        }


        protected virtual void OnChannelChanged(Channel oldValue, Channel newValue)
        {

        }

        [Category("Common")]
        public Channel channel
        {
            get
            {
                return (Channel)GetValue(ChannelProperty);
            }
            set
            {
                SetValue(ChannelProperty, value);
            }
        }

        #endregion
        #endregion Dependency Properties
        #region Constructor
        static DrumPatchTabPanel()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DrumPatchTabPanel), new FrameworkPropertyMetadata(typeof(XA2TabPanelBase)));
        }
        public DrumPatchTabPanel()
        {            
            XA2Sequencer.TotalBarsIncreasedEvent += XA2Sequencer_TotalBarsChangedEvent;
            
        }
        void XA2Sequencer_TotalBarsChangedEvent(object sender, RoutedEventArgs e)
        {            
                AddNewRhythmButtonBar();
        }
        #endregion Constructor
        #region Event Overrides
        /// <summary>
        /// The respective DrumPatchHost for this DrumPatchTabPanel is created here.        
        /// </summary>
        public override void OnApplyTemplate()
        {
            GetTemplateChildren();                               
            SelectedTabChanged_OnRaiseEvent(DrumPatchControl.CurrentTab, new RoutedEventArgs());           
            SoundEngine = new DrumPatchHost();
            PrimarySubmixer = SoundEngine.SubMixer2;

            var panel = TabSubmixerPanel as StackPanel;
            if (SoundEngine.SubMixer != null && panel != null)
            {
                FilterPanel filter = new FilterPanel(SoundEngine.SubMixer2);
                panel.Children.Add(filter);
                if (TabSubmixerPanel != null)
                {
                    FxChain = new Collection<EffectDescriptor>();
                }
            }
        }
        #endregion Event Overrides
        #region Public Methods
        internal override void RefreshTabPatternPanel(bool isVisible)
        {            
                if (!isVisible)
                {
                    TabPatternPanel.Children.Clear();
                }
                if (isVisible)
                {
                    TabPatternPanel.Children.Clear();
                    foreach (RhythmButtonBar rbb in Bars)
                    {
                        TabPatternPanel.Children.Add(rbb);
                    }
                }            
        }
        internal override void TabPatternPanelRemoveBar()
        {
            if (Bars != null && Bars.Count > 0)
            {
                Bars.Remove(Bars[Bars.Count - 1]);
                RefreshTabPatternPanel(true);
            }
        }
        public override void Dispose()
        {
            IsTerminal = true;
            Engine.DisposeAHost(SoundEngine);  
        }
        public override void AddNewRhythmButtonBar()
        {
            if (TabPatternPanel != null)
            {               
                Bars.Add(XA2Sequencer.RegisterRhythmButtonBar(this));               
            }
        }
        #endregion Public Methods

      

        #region Event Handlers
     
        /// <summary>
        /// we have two options from the start.
        /// 
        /// 1.  TabShapePanel exists.  Carry on.
        /// 
        /// 2.  TabShapePanel does not exist
        /// (Happens when the current instance is new and has not been previously selected yet)
        /// 
        /// need to force the tabshapepanel to exist or set up an async callback for when it does exist.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        
        public void DoNothing()
        { }
        #endregion Event Handlers
    }
}
